using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Network.Delegate;
using Network.Tcp.Awaitable;
using Network.Tcp.NetSession;
using Network.Tcp.TcpConfig;
using System.Threading.Tasks;

namespace Network.Tcp
{
    public class ClientAgent : NetEngineBased, IDisposable
    {
        private bool _isruning = true;
        private SessionType _sessionType = SessionType.Packet;
        #region 构造函数
        internal ClientAgent(
            SessionType sessionType,
            ClientConfig cfg,
            NotifyEventHandler<CompleteNotify, Session> completetionNotify)
            : base(sessionType, cfg, completetionNotify)
        {
            _sessionType = sessionType;
            //Packet模式下启用心跳时启动一个心跳线程
            if (cfg.AppKeepAlive &&
                sessionType == SessionType.Packet)
            {
                Task.Run(() => AppKeepAliveWorkThread());
            }
        }
        #endregion
        #region 心跳线程
        private void AppKeepAliveWorkThread()
        {
            byte[] emptyHeart = new byte[] { 0, 0, 0, 0 };
            while (_isruning)
            {
                //遍历所有Session
                for (int i = 0; i < _sessions.Count; i++)
                {
                    var session = (PackSessionBased)_sessions[i];
                    if (session.State == ConnectionState.Closed ||
                    session.State == ConnectionState.None)
                    {
                        _logger.WriteLog("client_heart_thread = Closed || None");
                        _sessions.RemoveAt(i); i--; //从列表里删除无效的Session
                        continue;
                    }
                    //正在连接的Session不发送心跳包
                    if (session.State == ConnectionState.Connecting)
                        continue;
                    //心跳超时20秒
                    if ((int)(DateTime.Now - session.HeartTime).TotalSeconds > 20)
                    {
                        _logger.WriteLog("心跳线程超时 ! state：" + session.State.ToString() + " present_time：" + DateTime.Now.ToString() + " heart_time：" + session.HeartTime.ToString());
                        //已连接但心跳失败的Session直接移出列表
                        if (session.State == ConnectionState.Connected)
                        {
                            session.Close(true);
                            _sessions.RemoveAt(i); i--;
                        }
                    }
                    else
                    {
                        //如果数据正在发送，就不发送心跳 isuchannel=0时表示未被占用
                        if (session._isuchannel == 0)
                        {
                            var awaiter = _awaiterPool.Take();
                            //4个字节空包头
                            awaiter.Args.SetBuffer(emptyHeart, 0, emptyHeart.Length);
                            NetHelper.SendAsync(session.Socket, awaiter, (a, e) => _awaiterPool.Return(a));
                        }
                    }
                }
                Thread.Sleep(5000);
            }
        }
        #endregion
        #region 连接服务器
        public void ConnectToServer(IPEndPoint ipEndPoint)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            var awaiter = _awaiterPool.Take();
            var session = _sessionPool.Take();
            //设置正在连接状态
            session.State = ConnectionState.Connecting;

            awaiter.Args.RemoteEndPoint = ipEndPoint;

            NetHelper.ConnectAsync(socket, awaiter, (a, e) =>
             {
                 _awaiterPool.Return(a); //返还对象
                 if (e != SocketError.Success)
                 {
                     _logger.WriteLog("连接失败,错误:" + e.ToString());
                     //触发通知事件
                     _completetionNotify?.Invoke(CompleteNotify.OnClosed, session);
                     //返还session到池
                     _sessionPool.Return(session);
                     return;
                 }
                 //连接成功后将session放到列表中
                 _sessions.Add(session);
                 session.Attach(socket);
                 //触发通知事件
                 _completetionNotify?.Invoke(CompleteNotify.OnConnected, session);
                 //开始接收数据
                 session.StartProcess();
             });
        }
        #endregion
        #region 发送广播包
        public override void Broadcast(byte[] data)
        {
            Broadcast(data, 0, data.Length);
        }
        public override void Broadcast(byte[] data, int offset, int length)
        {
            if (_sessionType == SessionType.Full)
            {
                foreach (FullSessionBased session in _sessions)
                {
                    session.SendAsync(data, offset, length);
                }
            }
            else
            {
                foreach (PackSessionBased session in _sessions)
                {
                    session.SendAsync(data, offset, length);
                }
            }
        }
        #endregion
        #region 断开所有连接
        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="notify">是否触发通知</param>
        public override void ClearConnections(bool notify)
        {
            foreach (Session session in _sessions)
                session.Close(notify);

            _sessions.Clear();
        }
        #endregion
        #region 析构函数
        public override void Dispose()
        {
            if (_isruning)
            {
                _isruning = false;
                _logger.Dispose();
                ClearConnections(false);
                _awaiterPool.Dispose();
                _sessionPool.Dispose();
            }
        }
        #endregion
    }
}
